import React, { useRef } from "react";
import shallow from 'fast-deep-equal';
// import { useShallow } from 'zustand/react/shallow';
import { createSelectors } from './lib/createSelector';
import { StoreType, useBoundStore } from "./store";
import { usePersonStore } from "./store/person";

// MARK: 7、通过 createSelectors 可以不需要使用 useBoundStoreBase 直接获取数据
const boundStore = createSelectors(useBoundStore).use;

function BearCount() {
  // const bears = useBoundStoreBase(state => state.bears);
  return <h1>{boundStore.bears()} bears around here...</h1>
}

function PersonCount() {
  const person = usePersonStore(state => state.person);
  return <h1>{person} person around here...</h1>
}

function FishCount() {
  // const bears = useBoundStoreBase(state => state.bears);
  return <h1>{boundStore.fish()} fishes around here...</h1>
}

function MealKeys() {
  console.log('MealKeys rerender');
  // MARK: 9、使用 useShallow 来避免无用渲染
  // const keys = useBoundStore(state => Object.keys(state));
  const keys = useBoundStore(useShallow(state => Object.keys(state)));

  return <div>{keys.join(', ')}</div>
}

function Controls() {
  console.log('rerender');
  /* const { addBear, removeAllBears } = useBoundStore(state => ({
    addBear: state.addBear,
    removeAllBears: state.removeAllBears
  })); */
  const addBear = boundStore.addBear();
  const removeAllBears = boundStore.removeAllBears();
  const addFish = boundStore.addFish();
  // const removeAllBearFish = boundStore.removeAllBearFish();
  const asyncAddFish = boundStore.asyncAddFish();

  // MARK: 2、通过 useStore 获取 state 和 action
  const removeAllBearFish = useBoundStore(state => state.removeAllBearFish);
  
  return (
    <div style={{marginBottom: '20px'}}>
      <button onClick={() => {
        addBear();
      }}>add a bear</button>

      <button onClick={removeAllBears}>reset all bear</button>

      <button onClick={() => {
        addFish(10);
      }}>add ten fish</button>

      <button onClick={() => {
        removeAllBearFish();
      }}>reset all fish and bear</button>

      <button onClick={async () => {
        const res = await asyncAddFish();
        console.log('res ---> ', res);
      }}>async add fish</button>

      <button onClick={removeAllBearFish}>add person</button>
    </div>
  )
}

function useShallow<S, U>(selector: (state: S) => U): (state: S) => U {
  const prev = useRef<U>()

  return (state) => {
    const next = selector(state)
    return shallow(prev.current, next)
      ? (prev.current as U)
      : (prev.current = next)
  }
}

const useBoundStoreSelector = <U,>(selector: (state: StoreType) => U) => useBoundStore(useShallow(selector));

function Test() {
  const { obj, setObj } = useBoundStoreSelector(state => ({ obj: state.obj, setObj: state.setObj }));
  // const { obj, setObj } = useBoundStore(useShallow(state => ({ obj: state.obj, setObj: state.setObj })));

  console.log('render');

  return <div>
    <div>{JSON.stringify(obj)}</div>
    <button onClick={() => {
      setObj({ a: 1 });
    }}>改变</button>
  </div>
}

const App = () => {
  return <div style={{ margin: '30px' }}>
    <Controls />
    <div>bear store</div>
    <BearCount />
    <PersonCount />
    <hr />
    <div>fish store</div>
    <FishCount />
    <MealKeys />
    <Test />
  </div>
};

export default App;
